package xdu.lz.stage3_classloader.chapter4;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class SimpleClassLoader extends ClassLoader {

    private static final String DEFAULT_DIR
            = "F:\\IDEA\\IDEA\\workspace\\multi-threaded-concurrency\\myclassloader1";

    private String dir = DEFAULT_DIR;

    private String classLoaderName;

    public SimpleClassLoader() {

    }

    public SimpleClassLoader(String classLoaderName) {
        this.classLoaderName = classLoaderName;
    }

    public String getDir() {
        return dir;
    }

    public void setDir(String dir) {
        this.dir = dir;
    }

    //指定加载器的父加载器
    public SimpleClassLoader(String classLoaderName, ClassLoader parent) {

        super(parent);
        this.classLoaderName = classLoaderName;
    }

    public String getClassLoaderName() {
        return classLoaderName;
    }

    /**
     * 重新loadClass方法，处理自定义的类，让自定义的加载器优先加载 ，打破双亲委托模式
     */
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class<?> clazz = null;
        /**
         * 处理加载系统必要的类 ，如Object。这种类还是要系统加载器去加载的
         */
        if (name.startsWith("java.")) {
            System.out.println("name = " + name);

            ClassLoader classLoader = ClassLoader.getSystemClassLoader();
            clazz = classLoader.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return clazz;
            }

        }

        //处理自定义的类，让自定义的加载器优先加载 ，打破双亲委托模式
        clazz = findClass(name);

        //如果没有找到，再让父加载器去加载
        if (clazz == null && getParent() != null) {
            getParent().loadClass(name);
        }
        return clazz;

    }

    /**
     * @param name package1.package2.AAA  ---> package1/package2/AAA.class
     * @return
     * @throws ClassNotFoundException
     */

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String classPath = name.replace(".", "/");

        File classFile = new File(dir, classPath + ".class");

        if (!classFile.exists()) {
            throw new ClassNotFoundException("The class [" + name + "] not find under+ [" + dir + " ]");
        }
        byte[] classBytes = loadClassBytes(classFile);
        if (classBytes == null) {
            throw new ClassNotFoundException("load the class [" + name + "] failed");
        }
        return this.defineClass(name, classBytes, 0, classBytes.length);
    }

    private byte[] loadClassBytes(File classFile) {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
             FileInputStream in = new FileInputStream(classFile)
        ) {
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.flush();
            return out.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }
}
